﻿namespace CommonUtilityInfrastructure.Tests
{
    using System.Collections.Generic;
    using System.Linq;
    using NUnit.Framework;
    using UsefulTools.ExtensionMethods;

    [TestFixture]
    public class SelectManyRecursiveTests
    {
        private class Node
        {
            public int Val { get; set; }

            public string Text { get; set; }

            public Node(int val, string text)
            {
                Val = val;
                Text = text;
                Children = new List<Node>();
            }

            public List<Node> Children { get; private set; }

            public override string ToString()
            {
                return "Val: " + Val + " Str: " + Text;
            }
        }

        private Node CreateTree()
        {
var o = new Node(0, "o");
    var a = new Node(1, "a");
        var ab = new Node(0, "ab");
            var aba = new Node(1, "aba");
    var b = new Node(0, "b");
        var ba = new Node(0, "ba");
            var baa = new Node(1, "baa");
            var bab = new Node(0, "bab");
            var bac = new Node(1, "bac");
                var baca = new Node(1, "baca");

o.Children.AddRange(new[] {a, b});
a.Children.AddRange(new[] {ab});
ab.Children.AddRange(new[] {aba});
b.Children.AddRange(new[] {ba});
ba.Children.AddRange(new[] {baa, bab, bac});
bac.Children.AddRange(new[] {baca});

            return o;
        }

        [Test]
        public void SelectManyRecursive_should_select_all_nodes_in_a_tree()
        {
            var o = CreateTree();
            var result = new[] {o}.SelectManyRecursive(n => n.Children).ToList();

            Assert.AreEqual(10, result.Count());
            Assert.AreEqual(10, result.Select(obj => obj.ToString()).Distinct().Count());
        }


        [Test]
        public void SelectManyRecursive_should_follow_nodes_deeper_only_when_predicate_is_true()
        {
            var o = CreateTree();
            var result = new[] {o}.SelectManyRecursive(n => n.Children, n => n.Val == 0).ToList();
            CollectionAssert.AreEquivalent(new[] { "o", "b", "ba", "bab" }, result.Select(_ => _.Text));
            
        }

        [Test]
        public void SelectManyRecursive_should_select_all_leaves_in_the_tree()
        {
            var o = CreateTree();
            var result = new[] {o}.SelectManyRecursive(n => n.Children, leafsOnly: true).ToList();

            Assert.AreEqual(4, result.Count());
        }

        [Test]
        public void SelectManyRecursive_should_go_deeper_when_predicate_is_true_and_select_only_leaves()
        {
            var o = CreateTree();
            var result = new[] {o}.SelectManyRecursive(n => n.Children, n => n.Val == 0, leafsOnly: true).ToList();

            Assert.AreEqual(1, result.Count());

            Assert.AreEqual("bab", result.Single().Text);
        }

    }
}

